import os
import re
import json
from pathlib import Path

# 定义 VS Code 配置文件路径
VSCODE_DIR = Path(".vscode")
CPP_PROPERTIES_FILE = VSCODE_DIR / "c_cpp_properties.json"

# 获取环境变量中的 GCC 路径
def find_gcc_path():
    paths = os.getenv("PATH", "").split(os.pathsep)
    for path in paths:
        if "gcc-arm-none-eabi" in path and Path(path).is_dir():
            return Path(path)
    return None

# 从 Makefile 提取 -I 指定的 include 路径
def extract_include_paths(makefile_path):
    include_paths = []
    if not makefile_path.exists():
        print(f"Makefile not found: {makefile_path}")
        return include_paths

    with open(makefile_path, "r") as file:
        lines = file.readlines()

    # 搜索 C_INCLUDES 或类似变量的定义
    include_pattern = re.compile(r"^\s*-I([^\s]+)")
    for line in lines:
        # 去除注释部分
        line = line.split("#")[0].strip()
        if not line:
            continue

        # 逐行检查是否包含 -I
        if "-I" in line:
            matches = include_pattern.findall(line)
            include_paths.extend(matches)

    # 去除重复路径并返回
    return list(set(include_paths))

# 从 Makefile 提取 -D 指定的宏定义
def extract_defines(makefile_path):
    defines = []
    if not makefile_path.exists():
        print(f"Makefile not found: {makefile_path}")
        return defines

    with open(makefile_path, "r") as file:
        lines = file.readlines()

    # 搜索 C_DEFS 或类似变量的定义
    define_pattern = re.compile(r"^\s*-D([^\s]+)")
    for line in lines:
        # 去除注释部分
        line = line.split("#")[0].strip()
        if not line:
            continue

        # 逐行检查是否包含 -D
        if "-D" in line:
            matches = define_pattern.findall(line)
            defines.extend(matches)

    # 去除重复定义并返回
    return list(set(defines))

# 更新或生成 c_cpp_properties.json 文件
def update_cpp_properties(gcc_path, include_paths, defines):
    if not VSCODE_DIR.exists():
        VSCODE_DIR.mkdir()

    # 默认配置模板
    config = {
        "configurations": [
            {
                "name": "STM32",
                "includePath": [],
                "defines": [],
                "compilerPath": "",
                "cStandard": "c11",
                "cppStandard": "c++17",
                "intelliSenseMode": "gcc-arm",
            }
        ],
        "version": 4,
    }

    # 如果文件已存在，读取现有内容
    if CPP_PROPERTIES_FILE.exists():
        with open(CPP_PROPERTIES_FILE, "r") as file:
            try:
                config = json.load(file)
            except json.JSONDecodeError:
                print("Error parsing existing c_cpp_properties.json. Using default configuration.")

    # 更新 includePath 和 compilerPath
    config["configurations"][0]["includePath"] = list(
        {str(Path(path).resolve()) for path in include_paths}
    )
    config["configurations"][0]["compilerPath"] = str(gcc_path / "arm-none-eabi-gcc")
    config["configurations"][0]["defines"] = [define for define in defines]

    # 写入文件
    with open(CPP_PROPERTIES_FILE, "w") as file:
        json.dump(config, file, indent=4)
    print(f"Updated {CPP_PROPERTIES_FILE}")

def main():
    # 定位 GCC 编译器路径
    gcc_path = find_gcc_path()
    if not gcc_path:
        print("GCC ARM toolchain not found in PATH. Please check your environment variables.")
        return

    print(f"Found GCC toolchain at: {gcc_path}")

    # 定位 Makefile 并提取 include 路径
    makefile_path = Path("Makefile")
    include_paths = extract_include_paths(makefile_path)
    if not include_paths:
        print("No include paths found in Makefile.")
    else:
        print(f"Extracted include paths: {include_paths}")
        
    # 提取 defines
    defines = extract_defines(makefile_path)
    if not defines:
        print("No defines found in Makefile.")
    else:
        print(f"Extracted defines: {defines}")

    # 更新 VS Code 配置文件
    update_cpp_properties(gcc_path, include_paths, defines)

if __name__ == "__main__":
    main()
